package com.ruoyi.app.util;

import com.ruoyi.app.config.AppConfig;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;

@Slf4j
public class AesUtil {

    private static final String ENCODING = "UTF-8";

    private static final String KEY_ALGORITHM = "AES";

    private static final int KEY_LENGTH = 128;
    private static final int KEY_GENERATOR_LENGTH = 256;

    //默认的加密算法
    private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";

    //AES-GCM
    private static final String GCM_CIPHER_ALGORITHM = "AES/GCM/NoPadding";

    private static byte[] getKey(String pwd) throws Exception {
        if (pwd.length() >= 16) {
            String bit128Str = pwd.substring(0, 16);
            return bit128Str.getBytes(ENCODING);
        } else {
            throw new Exception("请设置16位的AES秘钥");
        }
    }

    // 生成加密秘钥
    private static SecretKeySpec getSecretKey(String password) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(getKey(password), KEY_ALGORITHM);
        return keySpec;
    }

    //ECB加密
    public static byte[] encryptByPKCS5(byte[] content, String password) throws Exception {
        try {
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);

            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));

            return cipher.doFinal(content);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("AES加密异常");
        }
    }

    //ECB解密
    public static String decrypt(byte[] content, String password) throws Exception {
        try {
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);

            cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password));

            byte[] result = cipher.doFinal(content);

            String r = new String(result, ENCODING);
            return r;
        } catch (Exception e) {
            log.error("----------ECB解密异常 加密内容:" + content + "------------随机数 :" + password, e);
            throw new Exception("AES解密异常");
        }
    }

    // 生成加密秘钥
    public static String getGcmSecretKey() throws Exception {
        KeyGenerator generator = KeyGenerator.getInstance(KEY_ALGORITHM);
        //初始化密钥生成器，AES要求密钥长度为128位、192位、256位
        generator.init(KEY_GENERATOR_LENGTH);
        SecretKey secretKey = generator.generateKey();
        return Base64.encodeBase64String(secretKey.getEncoded());
    }

    //GCM加密
    public static String gcmEncrypt(String content, String keyStr) throws Exception {
        try {
            if (StringUtils.isEmpty(content) || StringUtils.isEmpty(keyStr)) {
                return null;
            }
            SecretKey secretKey = new SecretKeySpec(Base64.decodeBase64(keyStr), KEY_ALGORITHM);
            Cipher cipher = Cipher.getInstance(GCM_CIPHER_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] iv = cipher.getIV();
            assert iv.length == 12;// 偏移参数及长度要在解密的时候保持一致
            byte[] encryptData = cipher.doFinal(content.getBytes(ENCODING));
            assert encryptData.length == content.getBytes(ENCODING).length + 16;
            byte[] message = new byte[12 + content.getBytes(ENCODING).length + 16];
            System.arraycopy(iv, 0, message, 0, 12);
            System.arraycopy(encryptData, 0, message, 12, encryptData.length);
            return Base64.encodeBase64String(message);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("AES加密异常");
        }
    }

    //GCM解密
    public static String gcmDecrypt(String content, String keyStr) {
        try {
            if (StringUtils.isEmpty(content) || StringUtils.isEmpty(keyStr)) {
                throw new Exception("AESGCM256解密异常,检查文本或密钥");
            }
            Cipher cipher = Cipher.getInstance(GCM_CIPHER_ALGORITHM);
            SecretKey key = new SecretKeySpec(Base64.decodeBase64(keyStr), KEY_ALGORITHM);

            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] message = Base64.decodeBase64(content.getBytes(ENCODING));
            // 这里的12和16是加密的时候设置的偏移参数及加密长度
            if (message.length < 12 + 16) throw new IllegalArgumentException();
            GCMParameterSpec params = new GCMParameterSpec(KEY_LENGTH, message, 0, 12);
            cipher.init(Cipher.DECRYPT_MODE, key, params);
            byte[] decryptData = cipher.doFinal(message, 12, message.length - 12);
            String decript = new String(decryptData);
            return decript;
        } catch (Exception e) {
            log.error("----------GCM解密异常 加密内容:" + content + "------------随机数 :" + keyStr, e);
        }
        return null;
    }

    public static void main(String[] args) throws Exception {

        // 生成加密秘钥
//        String secretKey2 = getGcmSecretKey();
//        System.out.println("密钥: " + secretKey2 + "\n");
//        String cryptResult = gcmEncrypt("DATA Content", secretKey2);
//        System.out.println("加密结果: " + cryptResult + "\n");
//        String decryptResult = gcmDecrypt(cryptResult, secretKey2);
//        System.out.println("解密结果: " + decryptResult + "\n");


        AppConfig appConfig = new AppConfig();
        appConfig.setSecurityMock("0");
        appConfig.setSecurityEffectiveTime("60");
        appConfig.setServicePrivatekey("MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJ7Ed0ap0SEieKvbiTzvRqQ/SB5305ZgHj81w2Gle95Arka20fKofZcB8rIK07k6hIZFXC1wHxro74IDaTw5YXB7cz0eE86lWdeT37hPHfZyN+0VshnN1Zc1+TOYwORWRxX0uJqWHC+wfA0iFc9M68xeibFhxSaPqXsqIwhyUkVHAgMBAAECgYA/jHQRnLdQg/O5Fk6ATWYBKDM9vsi6UA7LTkG+O/awp0MamuK+NiLO5sC18w97/Kg+9lRG+7H3m3UCnUrqCC2vrtPJqvXaMintnjg5Qmeu9FQkAe2rHktzRwE1CPhy51eZqPBi6Zfsfy2OBtGGdL5YPopH/JXylyNkuiKXv9AUwQJBAMuRz6GTZ+xUUbF35EesioO4m3HJC77R/RRrE4IidLQJLosvjeN/5Te1Mmeeo3ike1gw3Ie1XD83cxfegLAa4sUCQQDHqKoBOsnL8/Vy3GVL50xF6I62PbbkFo7xVzNt2bvBrj2ZX7YsiD6xDA3SwB4a9ypUyQk/43P+kSUPdrZsLpibAkEAgZ1VlotEoDUPzu+HahtyFmx0jP51fAo4GcgTo8hMhlVSTUz6CuBkEhRNA6z+aNJRttVllQLkuVuU7J2/UmHMAQJAJ8TiyAfrtiJL26smyi2yNaKS+p3kVh5gLpZN+i2KhpOsVWaJJOmmgyGBh18ZIAnndqfsnbsymZxTo3bj8zx8zQJAffdYccEsiyxfz9VAgqDuFPHvybXx8AAosrogdRPJq998W9bA9o4zfNJTt0UUaNBmA8MofwBZ/GPAQnTfie2ASw==");
        appConfig.setServicePublickey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCexHdGqdEhInir24k870akP0ged9OWYB4/NcNhpXveQK5GttHyqH2XAfKyCtO5OoSGRVwtcB8a6O+CA2k8OWFwe3M9HhPOpVnXk9+4Tx32cjftFbIZzdWXNfkzmMDkVkcV9LialhwvsHwNIhXPTOvMXomxYcUmj6l7KiMIclJFRwIDAQAB");
        appConfig.setSginPrivatekey("MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANpNskwGRtDAJDEohnJ4g/uKXrSwzts7B5iqpP5hWhiT4aw3/IRgCVig25QNjHKRs1uYmjmk6mwTnUeI6MMfbPal/pIwLjDSGg1UrqxiVLAlklRNHs40HusY0S59iISmxq8VOmmO1WENBBOaVwl+9rR4ILlLDhhXPjXvJ2f7tSl1AgMBAAECgYArqoDwjgzaMqTKpHWILi0QQpRBBmDKH1ucoP2R2H1CD0qDvUsoW2FjNgHV8oPWYuiCeNrYjvFJHv9F0M/mP8H2kV+acRdVboma8lLqbowqKZi5xjwWE9V0IyfEPTDJu/i35S0HePLYceq5e6kyQgkctAV7aMW9TtFm+42+qPnx4QJBAP0zE3tI+FwSqZR+QlurlFDXSQHl6PtsPRpcRUYD1gSf1EFZdlWHoigPl/z8GQ0rdxS6tjow3D5wsAC85sCG140CQQDct9BSjczrdBOCXUarllPw85xzUS7OgsHStu3skS6R2yonnmJSgkUUbPdhE6lbIi+jNteSHvJim2Cw8gdl28uJAkEAh5qCNYXYFZ+dGL0iFuxmi4ExRYX3aCgI9YQzSZMmXOWojLM4EAiLDP+E++WcGRSNOxngHHwsiHhbmpmQz82nxQJASQBS2rsjx8yAl2Gaei4iXVN1r35uaMc+rB7s2o26RWujqa7s/jUv++1+dJE4Nng8IVOGQUITESIq/NtQLxRfYQJBANRc862mRGpT6NLkH0qAKj/GNI0BBWyIvV701ucEQZSMjVs8gsBnFENyWC4NaR5azxyGfNvpC7hoE6BIbSzBKBQ=");
        appConfig.setSginPublickey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhIJf1vdSbmbsngmXZ5DrgdOf/xHgrjxRvwmNFtVUsMeNDDfrHrjf1l8tb/HhHR2DnSnNIg7IIYM65SpfdJo3RbE6v5minSLvMU2vFGd5bh/8X3sBptztH8asegL4bMENOHfn2SEkDkxHIsv8c9oJ5gmpUO7CvHUPiDub1aZe+PwIDAQAB");


//        String reqRandom = "YsldwrpiPLLo6cHDLNNilU98rmvQSyi9Cr0gQuOOJK8=";
//        String encryptRandom = Base64.encodeBase64String(RsaUtil.encryptByPublickey(reqRandom.getBytes(), RsaUtil.getPublickey(appConfig.getServicePublickey())));
//        System.out.println("加密后Random：{}"+  encryptRandom);
//        ReqMsg(super=BaseMsg(data=jfqfEf0fwPxJAOp7qYMhXR2Z9yU/kNzQk4bt4lWM1yERh6kJTsmvcrI8msMq1G7IQ7sMnDUQGph0pWa5Ne0k8NJ55+i1qv3H), appId=app, channeld=app, random=yvILg6E9r3M9fXGQcjiJYucJodAdQZeun7m199OTHGQ=, sign=0yg/rn0PG1KXHtWeqN/c063aHVmEdQfskgepOnxCXzv1G/m7ClksEUlvvlhPiYSzd9k2V9MAiKbojXdAtNFy05DyzH8R+qp/LRXD3JvVsHfmBufZirdhsAeXL9PtCMOhh/piWuFL5lLwWGICqPpGv0gbnM7wZRRm5U4CPMUkrMc=, reqId=2e887a9d9db843d382072af985a11970, timestamp=1644567129919)
        String reqRandom = "Q0+B6LZZbahT7DWdohTeEiFYqiPvZRAG2OjPyc3GzZk=";
//        String cryptResult = gcmEncrypt("{\"noticeType\":\"\",\"type\":\"1\",\"verifyCode\":\"202020\"}", reqRandom);
//        System.out.println("当前加密结果: " + cryptResult );
//        String decryptResult = gcmDecrypt(cryptResult, reqRandom);
//        System.out.println("当前解密结果: " + decryptResult + "\n");

//                "Fygm2s4QFiyGnDCY/xuAJLFpVHONQndDf30St013yH4=";
//        byte[] resultRandom = RsaUtil.decryptByPrivateKey(Base64.decodeBase64(encryptRandom), RsaUtil.getPrivateKey(appConfig.getServicePrivatekey()));
//        System.out.println(" 随机数："+ reqRandom);
////        FROBPv02tpmJ7QOX9Kpi0XbYZt2myL/Hy78PKBVqeskZfm2Qvnsi/pZQ0jBSCdvpoha4f6WtAKc9o5oPqbKNAX/at51S3V/p4A==
        String data = "5l5KxAqtSuCCVYMUNgQL1iDfusi7g4AEkoKnllcRF9pV5ckavdnsjfOvIpeZfP5IWFYax5wX9tv7JI+8cd5GMPde4QsAV8w+";
////                "JMYhHPGdfN798qzgf7ybn4dZq51lf1Td2j4ig9QgYmviH1hBjIz8hziN8s2S+gDw8J+eSrTLw+rJ+yu5gudyoMuOjCIpMzWD";
//        String resultBizJsonStr = AesUtil.decrypt(Base64.decodeBase64(data), reqRandom);
        System.out.println("日志密文：" + data);
        String resultBizJsonStr = AesUtil.gcmDecrypt(data, reqRandom);
        System.out.println("日志解密结果：" + resultBizJsonStr);
    }

}